package com.gzx.risk.core.utils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Map;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class CryptoUtils {

    public enum SignType {
        MD5, SHA1
    }

    public static String SHA1(Object content) {
        return encryption("SHA-1", content);
    }

    public static String MD5(Object content) {
        return encryption("MD5", content);
    }

    private static String encryption(String type, Object content) {
        try {
            MessageDigest md = MessageDigest.getInstance(type);
            md.update(content.toString().getBytes("UTF-8"));
            byte[] hash = md.digest();
            StringBuilder secpwd = new StringBuilder();
            for (int i = 0; i < hash.length; i++) {
                int v = hash[i] & 0xFF;
                if (v < 16) {
                    secpwd.append(0);
                }
                secpwd.append(Integer.toString(v, 16));
            }
            return secpwd.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 将Map参数集合按key值排序 并封装成k1=v1&ke2=v2&....&kn=vn 的形式
     *
     * @param params 参数Map集合
     * @return
     */
    public static String sortParam(Map<String, ? extends Object> params) {
        StringBuilder sb = new StringBuilder();
//        jdk8 及以上版本的排序
		params.keySet().stream().sorted()
                .filter(k -> !"sign".equalsIgnoreCase(k)&&params.get(k)!=null)
                .forEach(k -> sb.append(k).append("=").append(params.get(k)).append("&"));
		return sb.length()>1?sb.substring(0, sb.length()-1):null;
    }


    /**
     * Map集合对参数进行签名
     *
     * @param params 参数Map集合
     * @param key    签名规则中的key
     * @return
     */
    public static String signParam(Map<String, ? extends Object> params, String key) {
        return signParam(sortParam(params), key);
    }

    /**
     * 对已经组装好的参数字符串进行签名
     *
     * @param params 参数字符串
     * @param key    签名key
     * @return
     */
    public static String signParam(String params, String key) {
        String signStr = key != null && key.length() > 0 ? params + key : params;
        return CryptoUtils.SHA1(signStr);
    }

    /**
     * 将 byte[] 计算为 MD5 值（32位小写）
     * @param bytes 字节数组（由 inputStreamToBytes 方法生成）
     * @return MD5 哈希值（32位小写字符串）
     * @throws NoSuchAlgorithmException 若 JVM 不支持 MD5 算法
     */
    public static String bytesToMD5(byte[] bytes) throws NoSuchAlgorithmException {
        if (bytes == null || bytes.length == 0) {
            throw new IllegalArgumentException("字节数组不能为空");
        }
        // 获取 MD5 消息摘要实例
        MessageDigest md = MessageDigest.getInstance("MD5");
        md.update(bytes); // 直接使用字节数组更新摘要
        byte[] digest = md.digest();

        // 转换为 32 位小写字符串
        StringBuilder sb = new StringBuilder();
        for (byte b : digest) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }

    /**
     * 将字符串压缩后Base64
     *
     * @param primStr 待加压加密函数
     * @return
     */
    public static String gzipString(String primStr) {
        if (primStr == null || primStr.length() == 0) {
            return primStr;
        }
        ByteArrayOutputStream out = null;
        GZIPOutputStream gout = null;
        try {
            out = new ByteArrayOutputStream();
            gout = new GZIPOutputStream(out);
            gout.write(primStr.getBytes(Charset.forName("Utf-8")));
            gout.flush();
        } catch (IOException e) {
            System.out.println("对字符串进行加压加密操作失败：" + e.fillInStackTrace());
            return null;
        } finally {
            if (gout != null) {
                try {
                    gout.close();
                } catch (IOException e) {
                    System.out.println("对字符串进行加压加密操作，关闭gzip操作流失败：" + e.fillInStackTrace());
                }
            }
        }
        return Base64.getEncoder().encodeToString(out.toByteArray());
    }

    /**
     * 将压缩并Base64后的字符串进行解密解压
     *
     * @param compressedStr 待解密解压字符串
     * @return
     */
    public static final String ungzipString(String compressedStr) {
        if (compressedStr == null) {
            return null;
        }
        ByteArrayOutputStream out = null;
        ByteArrayInputStream in = null;
        GZIPInputStream gin = null;
        String decompressed = null;
        try {
            byte[] compressed = Base64.getDecoder().decode(compressedStr);
            out = new ByteArrayOutputStream();
            in = new ByteArrayInputStream(compressed);
            gin = new GZIPInputStream(in);
            byte[] buffer = new byte[1024];
            int offset = -1;
            while ((offset = gin.read(buffer)) != -1) {
                out.write(buffer, 0, offset);
            }
            decompressed = out.toString("Utf-8");
        } catch (IOException e) {
            System.out.println("对字符串进行解密解压操作失败：" + e.fillInStackTrace());
            decompressed = null;
        } finally {
            if (gin != null) {
                try {
                    gin.close();
                } catch (IOException e) {
                    System.out.println("对字符串进行解密解压操作，关闭压缩流失败：" + e.fillInStackTrace());
                }
            }
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    System.out.println("对字符串进行解密解压操作，关闭输入流失败：" + e.fillInStackTrace());
                }
            }
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    System.out.println("对字符串进行解密解压操作，关闭输出流失败：" + e.fillInStackTrace());
                }
            }
        }
        return decompressed;
    }
}
